package com.fuluwa.infra.utils;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;

import org.apache.commons.lang.StringUtils;
import org.jdom.JDOMException;

public class HttpUtil {

	public static final String CHARSET_GBK = "GBK";
	public static final String CHARSET_UTF8 = "UTF-8";

	/**
	 * <p>
	 * 使用UTF-8编码请求URL并有UTF-8编码解析回包
	 * </p>
	 * 
	 * @param urlStr
	 * @param params
	 * @param connectTimeout
	 * @param readTimeOut
	 * @param requestCharset
	 * @param defaultResponseCharset
	 * @return
	 * @throws IOException
	 */
	public static String post(String urlStr, Map<String, String> params, String charset, String host, Proxy proxy,
			int connectTimeout, int readTimeOut) throws IOException {

		HttpURLConnection huc = null;
		try {
			if (StringUtils.isEmpty(charset)) {
				charset = CHARSET_UTF8;
			}
			URL url;
			String paramStr = StringUtil.trim(toQueryString(params, charset));
			url = new URL(urlStr);
			if (proxy != null) {
				huc = (HttpURLConnection) url.openConnection(proxy);
			} else {
				huc = (HttpURLConnection) url.openConnection();
			}

			huc.setConnectTimeout(connectTimeout);
			huc.setReadTimeout(readTimeOut);
			huc.setRequestMethod("POST");
			// TEST ONLY
			if (StringUtils.isNotEmpty(host)) {
				huc.setRequestProperty("Host", host);
			}
			huc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
			if (!StringUtil.isEmpty(paramStr)) {
				huc.setDoOutput(true);
				OutputStreamWriter wr = new OutputStreamWriter(huc.getOutputStream(), charset);
				wr.write(paramStr);
				wr.flush();
			}
			InputStream is = huc.getInputStream();
			byte[] buf = new byte[1024];
			ByteArrayOutputStream bos = new ByteArrayOutputStream(2048);
			int length = -1;
			while ((length = is.read(buf)) >= 0) {
				bos.write(buf, 0, length);
			}
			buf = bos.toByteArray();
			return new String(buf, charset);
		} finally {
			if (huc != null)
				huc.disconnect();
		}
	}

	/**
	 * GET
	 * 
	 * @param urlStr
	 * @param params
	 * @param connectTimeout
	 * @param readTimeOut
	 * @param requestCharset
	 * @return
	 * @throws IOException
	 * @throws JDOMException
	 */
	public static String get(String urlStr, Map<String, String> params, String charset, String host, Proxy proxy,
			int connectTimeout, int readTimeOut) throws IOException {
		HttpURLConnection huc = null;
		try {
			if (StringUtils.isEmpty(charset)) {
				charset = CHARSET_UTF8;
			}
			URL url;
			String paramStr = StringUtil.trim(toQueryString(params, charset));
			if (!StringUtil.isEmpty(paramStr)) {
				urlStr = urlStr.indexOf('?') > 0 ? urlStr + '&' + paramStr : urlStr + '?' + paramStr;
			}
			url = new URL(urlStr);
			if (proxy != null) {
				huc = (HttpURLConnection) url.openConnection(proxy);
			} else {
				huc = (HttpURLConnection) url.openConnection();
			}
			huc.setConnectTimeout(connectTimeout);
			if (StringUtils.isNotEmpty(host)) {
				huc.setRequestProperty("Host", host);
			}
			huc.setReadTimeout(readTimeOut);
			huc.setRequestMethod("GET");
			huc.connect();
			InputStream is = huc.getInputStream();
			byte[] buf = new byte[1024];
			ByteArrayOutputStream bos = new ByteArrayOutputStream(2048);
			int length = -1;
			while ((length = is.read(buf)) >= 0) {
				bos.write(buf, 0, length);
			}
			buf = bos.toByteArray();
			return new String(buf, charset);
		} finally {
			if (huc != null)
				huc.disconnect();
		}
	}

	/**
	 * 生成query string串
	 * 
	 * @param params
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	public static String toQueryString(Map<String, String> params) throws UnsupportedEncodingException {
		return toQueryString(params, null);
	}

	/**
	 * 生成query string串
	 * 
	 * @param params
	 * @param charset
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	public static String toQueryString(Map<String, String> params, String charset) throws UnsupportedEncodingException {
		if (null == params || params.size() == 0) {
			return null;
		}
		StringBuilder str = new StringBuilder("");
		for (Map.Entry<String, String> e : params.entrySet()) {
			appendParam(e.getKey(), e.getValue(), str, "&", charset);
		}
		return str.toString();
	}

	/**
	 * 生成QueryMap 串，需要先做encode吗？？
	 * 
	 * @param params
	 * @param charset
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	public static Map<String, String> toQueryMap(String str) {
		Map<String, String> queryMap = new HashMap<String, String>();
		if (StringUtil.isEmpty(str)) {
			return queryMap;
		}
		StringTokenizer st = new StringTokenizer(str, "&");
		while (st.hasMoreElements()) {
			String s = (String) st.nextElement();
			String[] pare = s.split("=");
			if (pare.length == 1) { // 如果value为空
				queryMap.put(pare[0], "");
			} else if (pare.length > 1) {
				queryMap.put(pare[0], pare[1]);
			}
		}
		return queryMap;

	}

	public static Map<String, String> encodeQueryMap(Map<String, String> queryMap, String charSet)
			throws UnsupportedEncodingException {
		Map<String, String> result = new HashMap<String, String>();
		if (null == queryMap) {
			return result;
		}
		for (java.util.Map.Entry<String, String> entry : queryMap.entrySet()) {
			String key = entry.getKey();
			String value = entry.getValue();
			result.put(key, URLEncoder.encode(value, charSet));
		}
		return result;

	}

	/**
	 * 
	 * @param key
	 * @param value
	 * @param sb
	 * @param ampersand
	 * @param charset
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	private static StringBuilder appendParam(String key, String value, StringBuilder sb, String ampersand,
			String charset) throws UnsupportedEncodingException {
		if (sb.length() > 0) {
			sb.append(ampersand);
		}
		if (charset != null) {
			sb.append(URLEncoder.encode(key, charset));
		} else {
			sb.append(key);
		}
		sb.append("=");
		if (value != null) {
			if (charset != null) {
				sb.append(URLEncoder.encode(value, charset));
			} else {
				sb.append(value);
			}
		}
		return sb;
	}

	public static String postWithoutEncode(String urlStr, Map<String, String> params, String charset, String host,
			Proxy proxy, int connectTimeout, int readTimeOut, String cookieStr) throws IOException {

		HttpURLConnection huc = null;
		try {
			if (StringUtils.isEmpty(charset)) {
				charset = CHARSET_UTF8;
			}
			URL url;
			String paramStr = StringUtil.trim(toQueryString(params, charset));
			url = new URL(urlStr);
			if (proxy != null) {
				huc = (HttpURLConnection) url.openConnection(proxy);
			} else {
				huc = (HttpURLConnection) url.openConnection();
			}

			huc.setConnectTimeout(connectTimeout);
			huc.setReadTimeout(readTimeOut);
			huc.setRequestMethod("POST");
			// TEST ONLY
			if (StringUtils.isNotEmpty(host)) {
				huc.setRequestProperty("Host", host);
			}
			if (!StringUtil.isEmpty(cookieStr)) {
				huc.setRequestProperty("Cookie", cookieStr);
			}
			huc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
			if (!StringUtil.isEmpty(paramStr)) {
				huc.setDoOutput(true);
				OutputStreamWriter wr = new OutputStreamWriter(huc.getOutputStream(), charset);
				wr.write(paramStr);
				wr.flush();
			}
			InputStream is = huc.getInputStream();
			byte[] buf = new byte[1024];
			ByteArrayOutputStream bos = new ByteArrayOutputStream(2048);
			int length = -1;
			while ((length = is.read(buf)) >= 0) {
				bos.write(buf, 0, length);
			}
			buf = bos.toByteArray();
			return new String(buf, charset);
		} finally {
			if (huc != null)
				huc.disconnect();
		}
	}

	public static Proxy getProxy(String proxyIpAndPort) {
		// if("local".equals(System.getProperty("qgo.cfg.env"))){
		// return null;
		// }
		if (StringUtils.isEmpty(proxyIpAndPort)) {
			return null;
		}
		String[] ss = proxyIpAndPort.split(":");
		if (ss.length < 2) {
			return null;
		}
		return new Proxy(Proxy.Type.HTTP, new InetSocketAddress(ss[0], Integer.valueOf(ss[1])));
	}
}